PHP的PDO(PHP Data Objects)库封装的数据库查询函数

一个用PHP的PDO(PHP Data Objects)库封装的数据库查询函数。PDO是一个数据库抽象层,它提供了一个数据库抽象层,这意味着在不更改PHP代码的情况下更换数据库引擎。下面是对这段代码的详细解释:

函数定义:

  • query($sql, $sql_param = array(), $source_function = '', $display_error = true, $num = false): 这是一个名为query的函数,它接受五个参数:
    • $sql:要执行的SQL语句。
    • $sql_param:一个数组,包含SQL语句中的参数。
    • $source_function:一个字符串,表示调用此查询的源函数,可能用于错误跟踪。
    • $display_error:一个布尔值,决定是否显示错误信息。
    • $num:一个布尔值,决定是否只返回结果集中的第一列。

设置字符集:

  • 如果$this->set_names为真,那么会执行一个SET NAMES语句来设置MySQL客户端的字符集,确保数据的正确编码和解码。

预处理SQL语句:

  • 使用$this->dbh->prepare($sql)来预处理SQL语句。预处理可以帮助防止SQL注入攻击。

执行SQL语句:

  • 使用$sth->execute($sql_param)来执行SQL语句,并将参数传递给它。

错误处理:

  • 如果SQL执行失败,代码会捕获错误信息,并根据$display_error的值决定是否显示错误。如果显示错误,它会调用$this->display_error函数来显示错误信息。

异常处理:

  • 如果在执行过程中出现PDOException异常,代码会捕获这个异常,并获取其错误消息。然后,根据$display_error的值决定是否显示错误。

返回结果:

  • 如果$num为真,函数将返回结果集中的第一列。
  • 如果SQL语句是INSERT类型,函数将返回最后一次INSERT操作中生成的ID。
  • 如果结果集中的列数为0,函数将返回一个空数组。
  • 否则,函数将返回结果集中所有行的数组,每行都是一个关联数组。

这个函数的目的是提供一个方便、安全的方式来执行SQL查询,并处理可能出现的错误。它使用了PDO的预处理功能来防止SQL注入,并提供了错误处理和结果返回的功能。


   // pdo封装,执行SQL,错误时为false
   public function query($sql, $sql_param = array(), $source_function = '', $display_error = true, $num = false)
   {
       try {

           if ($this->set_names) {
               $sth = $this->dbh->prepare("set names $this->charset_mysql"); // 设置客户端的字符集,确保数据的正确编码和解码
               $sth->execute();
           }

           $sth = $this->dbh->prepare($sql); // SQL预处理

           if (!$sth->execute($sql_param)) {
               // 执行SQL(字段和值放入$sql_param参数中)
               $arr   = $sth->errorInfo();
               $error = $arr[0] . " " . $arr[2];
               if ($display_error) {
                   // 显示错误
                   $this->display_error("$error\n\nsql: $sql\narr_sql_param: " . print_r($sql_param, true), $source_function, true);
               }
               return false;
           }

       } catch (PDOException $e) {

           $error = $e->getMessage();
           if ($display_error) {
               $this->display_error("$error\n\nsql: $sql\narr_sql_param: " . print_r($sql_param, true), $source_function, true);
           }
           return false;
       }

       if ($num) {
           return $sth->fetchColumn(); // 从结果集中获取第一列
       }

       if (preg_match('/^insert/i', ltrim($sql))) {
           return $this->cast_id($this->dbh->lastInsertId()); // 返回最后一次INSERT操作中生成的ID
       }

       if ($sth->columnCount() == 0) {
           // 结果集中的列数等于0
           return array();
       }

       return $sth->fetchAll(PDO::FETCH_ASSOC); // 结果集中所有行的数组

   }
 

改进这段代码,可以考虑以下几个方面:

日志记录:增加更详细的日志记录功能,以便在出现问题时能够更容易地进行调试。

参数绑定:确保所有的SQL参数都是通过绑定机制传递的,而不是直接将参数插入到SQL语句中,这有助于防止SQL注入攻击。

返回结果处理:根据查询的类型(SELECT, INSERT, UPDATE, DELETE等)提供更细粒度的结果处理。

异常处理:在捕获到异常时,可以考虑提供更多的上下文信息,如SQL语句、参数等,以便更好地定位问题。

性能优化:如果可能,对查询进行优化,比如使用索引、减少不必要的数据加载等。

事务处理:如果函数涉及到多个数据库操作,考虑使用事务来确保数据的一致性。

代码复用:将重复的代码块抽象成方法,以提高代码的可读性和可维护性。

代码注释:添加必要的注释,解释代码的功能和逻辑,以便其他开发者更容易理解。

以下是一个改进后的示例代码:
public function query($sql, $sql_param = array(), $source_function = '', $display_error = true)
{
   try {
       // 设置字符集(如果需要)
       if ($this->set_names) {
           $this->executeNonQuery("set names $this->charset_mysql");
       }

       // 准备SQL语句
       $stmt = $this->prepare($sql);

       // 绑定参数并执行查询
       $stmt->execute($sql_param);

       // 根据SQL类型处理结果
       switch (trim(substr($sql, 0, 6))) {
           case 'SELECT':
               // 返回结果集
               return $stmt->fetchAll(PDO::FETCH_ASSOC);
           case 'INSERT':
               // 返回插入的ID
               return $this->lastInsertId();
           case 'UPDATE':
           case 'DELETE':
               // 返回受影响的行数
               return $stmt->rowCount();
           default:
               // 其他类型的SQL,返回空结果
               return array();
       }
   } catch (PDOException $e) {
       // 记录错误日志
       $this->logError($e->getMessage(), $sql, $sql_param, $source_function);

       // 如果需要显示错误,则抛出异常或返回false
       if ($display_error) {
           throw $e; // 可以选择抛出异常,或者在生产环境中返回false
       }

       return false;
   }
}

// 辅助方法:执行非查询SQL(如SET语句)
private function executeNonQuery($sql)
{
   $stmt = $this->dbh->prepare($sql);
   $stmt->execute();
   return $stmt;
}

// 辅助方法:记录错误日志
private function logError($errorMessage, $sql, $sql_param, $source_function)
{
   // 实现日志记录逻辑
   // 可以将错误信息、SQL语句、参数和源函数名记录到日志文件或数据库中
}
GoodText.cn在这个改进版本中,我添加了一个logError方法来处理错误日志记录,以及一个executeNonQuery辅助方法来执行非查询SQL语句。此外,我还对返回结果的处理进行了改进,根据不同的SQL类型返回不同的结果。我还保留了异常处理逻辑,但选择抛出异常而不是直接返回false,这样可以在上层调用中根据需要进行更灵活的错误处理。



创建日期是 2024-11-24 07:35:19pm